package com.link_with_health.controller;

import com.alibaba.fastjson.JSONObject;
import com.link_with_health.common.Page;
import com.link_with_health.common.Result;
import com.link_with_health.common.TokenMap;
import com.link_with_health.exception.NullQueryResultException;
import com.link_with_health.model.AdminLogEntity;
import com.link_with_health.model.AdminUserEntity;
import com.link_with_health.model.InfoTypeEntity;
import com.link_with_health.model.PatientEntity;
import com.link_with_health.model.SysInfoEntity;
import com.link_with_health.model.UserEntity;
import com.link_with_health.service.AdminLogService;
import com.link_with_health.service.SysInfoService;
import com.link_with_health.utils.JsonUtil;
import com.link_with_health.webSocket.NotificationServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

@Controller
@RequestMapping("/api/sysInfo")
public class SysInfoController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private final String AUTH_TOKEN = "Authorization";
    private TokenMap tokenMap = TokenMap.getInstance();

    @Resource(name = "sysInfoService")
    SysInfoService sysInfoService;

    @Resource(name = "adminLogService")
    AdminLogService adminLogService;

    /**
     * 获取通知信息
     * @param json 数据 json{method : '', params: {} }
     * @param request 请求
     * @return 结果
     */
    @PostMapping("/findSysInfo")
    @ResponseBody
    public Result findSysInfo(@RequestBody JSONObject json
            , HttpServletRequest request){

        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签验证失败";

        if(token==null|| !tokenMap.containsKey(token)){
            logger.error("[get sysInfo info failed]");
            return Result.fail(msg);

        }

        try {

            String method = json.getString("method");
            String paramsStr = json.getJSONObject("params").toJSONString();

            HashMap<String, Object> params = JsonUtil.json2obj(paramsStr
                    , HashMap.class);

            return method(method,params);

        } catch (Exception e){
            logger.error("[get sysInfo failed]",e);
            msg = "查找失败";

            if(e instanceof NullQueryResultException){
                return Result.notResult("无查找结果","NULL");
            }
        }

        return Result.fail(msg);
    }

    /**
     * 修改通知信息
     * @param json 数据
     * @param request 请求
     * @return 结果
     */
    @PostMapping("/modifySysInfo")
    @ResponseBody
    public Result modifySysInfo(@RequestBody JSONObject json
            , HttpServletRequest request){

        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签验证失败";

        if(token==null|| !tokenMap.containsKey(token)){
            logger.error("[modify sysInfo info failed]");
            return Result.fail(msg);
        }

        Integer adminId = Math.toIntExact(tokenMap.get(token)
                instanceof AdminUserEntity
                ? ((AdminUserEntity) tokenMap.get(token)).getAdminID()
                : ((UserEntity) tokenMap.get(token)).getUserId());


        try {

            SysInfoEntity entity = JsonUtil.json2obj(json.toJSONString()
                    , SysInfoEntity.class);

            SysInfoEntity oldEntity = sysInfoService.getSysInfoById(entity.getId());

            sysInfoService.changeInfo(entity);

            entity = sysInfoService.getSysInfoById(entity.getId());

            //记录消息
            String object = JsonUtil.obj2json(oldEntity);
            AdminLogEntity log = new AdminLogEntity(0L, adminId
                    , "修改", "sysInfo", object);
            adminLogService.addAdminLog(log);

           return Result.success("操作成功",entity);

        } catch (Exception e){
            logger.error("[modify failed]",e);
            msg = "操作失败";
        }

        return Result.fail(msg);
    }

    /**
     * 添加通知信息
     * @param json 数据
     * @param request 请求
     * @return 结果
     */
    @PostMapping("/addSysInfo")
    @ResponseBody
    public Result addSysInfo(@RequestBody JSONObject json
            , HttpServletRequest request){
        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签验证失败";

        if(token==null|| !tokenMap.containsKey(token)){
            logger.error("[add sysInfo info failed]");
            return Result.fail(msg);
        }

        Integer adminId = Math.toIntExact(tokenMap.get(token)
                instanceof AdminUserEntity
                ? ((AdminUserEntity) tokenMap.get(token)).getAdminID()
                : ((UserEntity) tokenMap.get(token)).getUserId());

        try {
            SysInfoEntity entity = JsonUtil.
                    json2obj(json.toJSONString(),SysInfoEntity.class);

            sysInfoService.addSysInfo(entity);

            entity = sysInfoService.getSysInfoById(entity.getId());

            String str = JsonUtil.obj2json(entity);

            //10000表示全体
            if(entity.getReceiver() != 10000L)
                //广播
                NotificationServer.sendMessageInController(str
                        , String.valueOf(entity.getReceiver()));
            else
                NotificationServer.sendMessageForAll(str);

            //记录
            String object = JsonUtil.obj2json(entity);
            AdminLogEntity log = new AdminLogEntity(0L, adminId
                    , "修改", "patient", object);
            adminLogService.addAdminLog(log);


            return Result.success("操作成功",entity);

        } catch (Exception e){
            logger.error("[add sysInfo failed]",e);
            msg = "操作失败";
        }

        return Result.fail(msg);
    }

    /**
     * 删除通知信息
     * @param json 数据 ids
     * @param request 请求
     * @return 结果
     */
    @PostMapping("/deleteSysInfo")
    @ResponseBody
    public Result deleteSysInfo(@RequestBody JSONObject json
            , HttpServletRequest request){

        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签验证失败";

        if(token==null|| !tokenMap.containsKey(token)){
            logger.error("[delete sysInfo info failed]");
            return Result.fail(msg);
        }

        Integer adminId = Math.toIntExact(tokenMap.get(token)
                instanceof AdminUserEntity
                ? ((AdminUserEntity) tokenMap.get(token)).getAdminID()
                : ((UserEntity) tokenMap.get(token)).getUserId());

        int errorNumber = 0;

        try {
            Long[] ids = json.getObject("ids",Long[].class);

            StringBuilder oldEntity = new StringBuilder();
            for(Long idBk : ids){
                SysInfoEntity entity = sysInfoService
                        .getSysInfoById(idBk);
                oldEntity.append("\n").append(JsonUtil.obj2json(entity));

                try{
                    sysInfoService.deleteSysInfo(idBk);
                }catch (Exception e){
                    logger.error("[delete sysInfo info failed" +
                            " =>"+idBk+"]",e);
                    errorNumber++;
                }
            }

            AdminLogEntity log = new AdminLogEntity(0L, adminId
                    , "删除","patient", oldEntity.toString());
            adminLogService.addAdminLog(log);

            if(errorNumber == 0){
                return Result.success("操作成功","NULL");
            }

        } catch (Exception e){
            logger.error("[failed to delete total=> "+errorNumber+"]",e);
            msg = "失败删除条数"+errorNumber;
        }
        return Result.fail(msg);
    }

    /**
     * 获取通知信息
     * @param json 数据
     * @param request 请求
     * @return 结果
     */
    @PostMapping("/selectSysInfoById")
    @ResponseBody
    public Result selectSysInfoById(@RequestBody JSONObject json
            , HttpServletRequest request){
        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签验证失败";
        if(token == null || !tokenMap.containsKey(token)){
            logger.error("[get info failed by token]");
            return Result.fail(msg);
        }

        try {
            Long sysInfoId = json.getLong("sysInfoId");

            return Result.success(
                    sysInfoService.getSysInfoById(sysInfoId));

        } catch (Exception e){
            logger.error("[failed to get info by id]",e);
            msg = "获取信息失败";
        }

        return Result.fail(msg);
    }

    /**
     * 通过接收者的查看通知信息状态
     * @param json 数据 isRead ---  消息状态
     * @param request 请求
     * @return 结果
     */
    @PostMapping("/receiveUserSysInfo")
    @ResponseBody
    public Result receiveUserSysInfo(@RequestBody JSONObject json
            , HttpServletRequest request){
        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签验证失败";
        if(token == null || !tokenMap.containsKey(token)){
            logger.error("[get info failed by token]");
            return Result.fail(msg);
        }

        try {
            if(tokenMap.get(token) instanceof UserEntity){
                Long userId = ((UserEntity)tokenMap.get(token)).getUserId();
                List<SysInfoEntity> list = sysInfoService.getSysInfoByReceiver(userId);
                //所有用户都能获取到的信息 10000表示用户群体
                list.addAll(sysInfoService.getSysInfoByReceiver(10000L));

                //获取未读信息
                if ("notRead".equals(json.getString("isRead")))
                    list=list.stream().filter(SysInfoEntity
                            ->(!SysInfoEntity.getIsRead()))
                            .collect(Collectors.toList());

                return Result.success(list);
            }
            //管理员账号收到的信息同一发给10001账号，且信息共享
            else if(tokenMap.get(token) instanceof AdminUserEntity){
                List<SysInfoEntity> list = sysInfoService
                        .getSysInfoByReceiver(10001L);
                //获取未读信息
                if ("notRead".equals(json.getString("isRead")))
                    list=list.stream().filter(SysInfoEntity
                            ->(!SysInfoEntity.getIsRead()))
                            .collect(Collectors.toList());

                return Result.success(list);

            }

        } catch (Exception e){
            logger.error("[failed to get info]");
            msg = "获取信息数据失败";
            if(e instanceof NullQueryResultException){
                logger.warn("[not info]");
                return Result.notResult("暂无消息","NULL");
            }
        }

        return Result.fail(msg);
    }

    /**
     * 修改通知信息状态
     * @param json 数据 sysInfoId 消息id
     * @param request 请求
     * @return 结果
     */
    @PostMapping("/readSysInfo")
    @ResponseBody
    public Result readSysInfo(@RequestBody JSONObject json
            , HttpServletRequest request){
        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签验证失败";
        if(token == null || !tokenMap.containsKey(token)){
            logger.error("[get info failed by token]");
            return Result.fail(msg);
        }

        try {
            Long sysInfoId = json.getLong("sysInfoId");
            SysInfoEntity entity = sysInfoService.getSysInfoById(sysInfoId);
            entity.setIsRead(true);

            sysInfoService.changeInfo(entity);
            entity = sysInfoService.getSysInfoById(sysInfoId);

            return Result.success(entity);


        } catch (Exception e){
            logger.error("[failed to change info readType]",e);
            msg = "操作失败";
        }

        return Result.fail(msg);
    }

    /**
     * 获取信息类型
     * @param request 请求
     * @return 返回类型数据
     */
    @GetMapping("/accessInfoType")
    @ResponseBody
    public Result accessInfoType(HttpServletRequest request){
        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签验证失败";
        if(token == null || !tokenMap.containsKey(token)){
            logger.error("[get info type failed by token]");
            return Result.fail(msg);
        }

        try{
            List<InfoTypeEntity> entity = sysInfoService.getAllInfoType();
            return Result.success(entity);

        }catch (Exception e){
            logger.error("[get info type failed]",e);
            msg = "获取信息种类失败";
        }

        return Result.fail(msg);
    }

    private Result method(String method, Map<String,Object> params) throws Exception{
        List<SysInfoEntity> list = null;
        String msg = "";

        switch (method){
            case "all":{
                list = sysInfoService.getAllSysInfo();
            }
            break;

            case "all-page":{
                list = sysInfoService.getAllSysInfo();

                Integer current = (Integer) params.get("current");
                Integer size = (Integer) params.get("size");
                Page<SysInfoEntity> page = new Page<>(list, size, current);

                return Result.success(page.getPageDate());
            }

            case "userId-page":{
                String id = (String) params.get("id");
                try {
                    list = sysInfoService.getSysInfoByReceiver(Long.valueOf(id));
                }catch (Exception e){
                    logger.warn("[not result in receiver]");
                }
                try{
                    if(list != null)
                        list.addAll(sysInfoService.getSysInfoBySender(Long.valueOf(id)));
                    else
                        list = sysInfoService.getSysInfoBySender(Long.valueOf(id));
                }catch (Exception e){
                    logger.warn("[not result in sender]");
                }

                if(list == null || list.isEmpty())
                    throw new NullQueryResultException("[not result in sender or receiver]");

                Integer current = (Integer) params.get("current");
                Integer size = (Integer) params.get("size");
                Page<SysInfoEntity> page = new Page<>(list, size, current);

                return Result.success(page.getPageDate());
            }


            default:
                logger.error("unknown method=>" + method);
                return Result.fail("未知查找方法");
        }

        return Result.success("查找成功",list);
    }

}
